package slm.games.tris;

import slm.games.tris.DeviceListActivity;
 
import android.media.AudioManager;
import android.media.SoundPool;
import android.media.SoundPool.OnLoadCompleteListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.EditText;
import android.widget.TextView;
 
 
 
import android.widget.GridView;
 
 
import android.widget.Toast;
import android.util.Log;

public class MainActivity extends Activity {
   private static ImageAdapter imageAdapter = null;
   static final String TAG = "SlmTrisGame01";
   
// Message types sent from the BluetoothChatService Handler
   public static final int MESSAGE_STATE_CHANGE = 1;
   public static final int MESSAGE_READ = 2;
   public static final int MESSAGE_WRITE = 3;
   public static final int MESSAGE_DEVICE_NAME = 4;
   public static final int MESSAGE_TOAST = 5;
   
   public static final int MESSAGE_PLAYER_NAME = 6;
   public static final int MESSAGE_CONNECTING_TO_DEVICE = 7;
   public static final int MESSAGE_PLAYER_DISCONNECTED = 8;
   public static final int MESSAGE_CONNECTION_ACCEPTED_FROM_REMOTE_REQUEST = 9;
   public static final int MESSAGE_CONNECTION_DONE_TO_REMOTE_REQUEST = 10;
   
// Key names received from the BluetoothChatService Handler
   public static final String DEVICE_NAME = "device_name";
   public static final String TOAST = "toast";
   public static final String PLAYER_NAME = "player_name";
   public static final String CONNECTION_ACCEPTED = "connection_accepted";
   public static final String CONNECTION_DONE_TO_REMOTE_REQUEST = "connection_do_to_remote_request";
   
// Member object for the chat services
   private BluetoothChatService mChatService = null;
   
// Name of the connected device
   private String mConnectedDeviceName = null;
   
// String buffer for outgoing messages
   private StringBuffer mOutStringBuffer;
   
// Intent request codes
   private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
   private static final int REQUEST_ENABLE_BT = 3;
   
   // Local Bluetooth adapter
   private BluetoothAdapter mBluetoothAdapter = null;
   
   // for BT mode...
   private Boolean local_player_locked = false;
   
   private Menu menu = null;
   private Game game = null;
   
   private Player local_player = null;
   private boolean connection_accepted_from_remote_request = false;
   
   private AlertDialog exitDialog = null;
   private SoundPool soundPool = null;
   
   public boolean isConnection_accepted_from_remote_request() {
	return connection_accepted_from_remote_request;
}

public void setConnection_accepted_from_remote_request(
		boolean connection_accepted_from_remote_request) {
	this.connection_accepted_from_remote_request = connection_accepted_from_remote_request;
}

private boolean is_player_connected = false;
   
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
	    Log.d(TAG,"SlmTrisGame MainActivity Started");
		//Toast.makeText(MainActivity.this, "Activity Started",Toast.LENGTH_SHORT).show();
		
	    this.exitDialog = createExitDialog();
	    
	    
		setContentView(R.layout.activity_main);
		
		GridView gridview = (GridView) findViewById(R.id.gridview);
	    
		if (MainActivity.imageAdapter == null)
		{
			MainActivity.imageAdapter = new ImageAdapter(this);
			Log.d(TAG,"Image Adapter created");
			//Toast.makeText(MainActivity.this, "Image Adapter created!",Toast.LENGTH_LONG).show();
		}
		
		// Get local Bluetooth adapter
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        // If the adapter is null, then Bluetooth is not supported
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, "Bluetooth is not available. Game available in local mode only", Toast.LENGTH_LONG).show();
        }
		
		//Toast.makeText(MainActivity.this, "Setting adapter to gridview",Toast.LENGTH_LONG).show();
		gridview.setAdapter(MainActivity.imageAdapter);
        
		this.initGame(null);
		this.soundPool = createSoundPool();
		
		
	    gridview.setOnItemClickListener(new OnItemClickListener() {
	    	@Override
	        public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
	            
	    		if (is_player_connected)
	    		 	local_player_move(position);
	    		else
	    			doNextMove(position);
	        }
	    });
      
	    
	}
	
	private void local_player_move(int pos)
	{
		if (this.game!=null)
		{
			boolean moved = this.game.p1_move(pos);
			if (moved)
			{  
				//this.soundPool.play(soundID, leftVolume, rightVolume, priority, loop, rate)
				sendMessage(String.valueOf(pos));
				if (this.local_player.getPlayerSymbol()==Game.CROSS)
				MainActivity.imageAdapter.setToCross(pos);
				else
					MainActivity.imageAdapter.setToCircle(pos);
				check_for_winner();
			}
		}
	}
	
	private void doNextMove(int pos)
	{
		if (this.game!=null)
		{
			Player p = this.game.doNextMove(pos);
			if (p!=null)
			{  
				if (p.getPlayerSymbol()==Game.CROSS)
				{
				MainActivity.imageAdapter.setToCross(pos);
				}
				else
				{
					MainActivity.imageAdapter.setToCircle(pos);
				}
			  check_for_winner();
			}
			else 
				Toast.makeText(this, "Unable to move... player not found!", Toast.LENGTH_LONG).show();
		}
	}
	
	
	private void remote_player_move(int pos)
	{
		if (this.game!=null)
		{   Toast.makeText(this, "REMOTE PLAYER MOVE REQUEST:" + String.valueOf(pos),Toast.LENGTH_LONG).show();
			boolean moved = this.game.p2_move(pos);
			if (moved)
			{  
				if (this.game.getRemotePlayer().getPlayerSymbol()==Game.CROSS)
				MainActivity.imageAdapter.setToCross(pos);
				else
					MainActivity.imageAdapter.setToCircle(pos);
				
				check_for_winner();
			}
		}
	}
	
	private void check_for_winner()
	{
		if (this.game!=null)
		 {
			Player winner = this.game.check_for_winner();
			if (winner!=null)
			{
				String text = "*** " + winner.getNickname() + " is the winner!!! ***";
				 
				Toast.makeText(this, text, Toast.LENGTH_LONG).show();
				resetGameAfterDelay(2000);
			}
		 }
	}
	
	public void resetGame(View view)
	{
		this.resetGame();
	}
	
	private void initGame(String remotePlayerName)
	{
	  Log.d(TAG,"CALLED INITGAME WITH REMOTE_PLAYERNAME:" + remotePlayerName);
	  this.resetGame();
	  
	  String local_player_name = this.getLocalPlayerName();
	  try {
		this.local_player = new Player(local_player_name, Player.CROSS);
		Player remotePlayer = new Player(remotePlayerName, Player.CIRCLE);
		this.game = new Game(this.local_player, remotePlayer, isConnection_accepted_from_remote_request());
		MainActivity.imageAdapter.setAllToBlank();
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
		Log.e(TAG, "Error: GAME: " + String.valueOf(this.game) + "AD:" + String.valueOf(MainActivity.imageAdapter) + " PL:" +String.valueOf(this.local_player));
		Toast.makeText(this, "Unable to init the game:" + e.getMessage(), Toast.LENGTH_LONG).show();
	}
	}
	
	private void setRemotePlayerName(String remotePlayerName)
	{
		 if (this.game!=null)
		 {
			 this.game.getRemotePlayer().setNickname(remotePlayerName);
		 }
			//Toast.makeText(this, "Unable to create remote player:" + e.getMessage(), Toast.LENGTH_LONG).show();
		 
	}
	private void update_status_label(int bt_status, String info) {
		
		String msg = null;
		switch(bt_status)
		{
		case MESSAGE_CONNECTING_TO_DEVICE:
			msg = "Status: Connecting to " + info;
			break;
		
		case MESSAGE_PLAYER_NAME:
			msg = "Status: Connected to " + info;
			break;
		
		case MESSAGE_PLAYER_DISCONNECTED:
			msg = "Status: Not Connected";
		}
		
		if (msg!=null)
		{
		Log.d(TAG,"MESSAGE IN UPDATE STATUS:" +msg);
		TextView txt_status = (TextView) findViewById(R.id.txt_connection_status);
		txt_status.setText((CharSequence) msg);
		}
	}
			
	private String getLocalPlayerName()	
	{
		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		return sharedPreferences.getString("edit_player_name", "anonymous");
	}
	
	private void sendPlayerNameInfo()
	{
		 
		String playerName =  getLocalPlayerName();
		if (playerName!=null)
		{
			String message = MainActivity.PLAYER_NAME + ":" + playerName;
			Toast.makeText(this, "Sending Player Name info:" + message, Toast.LENGTH_LONG).show();
			this.sendMessage(message);
		}
		else Toast.makeText(this, "Unable to send Player Name info!", Toast.LENGTH_LONG).show();
	}
	
	/**
     * Sends a message.
     * @param message  A string of text to send.
     */
    private void sendMessage(String message) {
    	/*
    	if (!is_player_connected)
    	{
    		Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();
        return;
    	}
    	*/	
    	
        // Check that we're actually connected before trying anything
        if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
            Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();
            return;
        }

        // Check that there's actually something to send
        if (message.length() > 0) {
            // Get the message bytes and tell the BluetoothChatService to write
            byte[] send = message.getBytes();
            mChatService.write(send);

            // Reset out string buffer to zero and clear the edit text field
            mOutStringBuffer.setLength(0);
            //mOutEditText.setText(mOutStringBuffer);
            synchronized (local_player_locked) {
           	 local_player_locked = true;
           	 } 
        }
    }

	
	 // -------------------------------- Bluetooth handling --------------- //
	
	
	@Override
    public void onStart() {
        super.onStart();
         Log.e(TAG, "++ ON START ++");

        // If BT is not on, request that it be enabled.
        // setupChat() will then be called during onActivityResult
        if (!mBluetoothAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
        // Otherwise, setup the chat session
        } else {
            if (mChatService == null) setupBTCommunication();
        }
    }

	
	private int getPreferredPlayerMode()
	{
		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		String selectedValue = sharedPreferences.getString("game_mode", String.valueOf(Game.MODE_2_PLAYERS_LOCAL));
		//Toast.makeText(this, "Valore del game:" + selectedValue, Toast.LENGTH_LONG).show();
		int player_mode = Integer.parseInt(selectedValue);
		return player_mode;
	}
	private void update_menu_items()
	{
		if (this.menu==null)
			return;
		
		int player_mode = getPreferredPlayerMode();
		if (player_mode==Game.MODE_2_PLAYERS_LOCAL)
		{
			MenuItem connect_scan = menu.findItem(R.id.secure_connect_scan);
			connect_scan.setVisible(false);
			
			MenuItem discoverable = menu.findItem(R.id.discoverable);
			discoverable.setVisible(false);
		}
		else
		{
			MenuItem connect_scan = menu.findItem(R.id.secure_connect_scan);
			connect_scan.setVisible(true);
			
			MenuItem discoverable = menu.findItem(R.id.discoverable);
			discoverable.setVisible(true);
		}
	}
    @Override
    public synchronized void onResume() {
        super.onResume();
        this.update_menu_items();
        
        Log.e(TAG, "+ ON RESUME MCHAT SERVICE NULL ? " + String.valueOf(mChatService == null) );
        
        int player_mode = this.getPreferredPlayerMode();
        if (player_mode==Game.MODE_2_PLAYERS_BT)
        {
	        // Performing this check in onResume() covers the case in which BT was
	        // not enabled during onStart(), so we were paused to enable it...
	        // onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
	        if (mChatService != null) {
	            // Only if the state is STATE_NONE, do we know that we haven't started already
	            if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
	              // Start the Bluetooth chat services
	              mChatService.start();
	            }
	        }
        }
    }
	
    
    private void setupBTCommunication() {
        Log.d(TAG, "setupBTCommunication()");
 
        // Initialize the BluetoothChatService to perform bluetooth connections
        mChatService = new BluetoothChatService(this, mHandler);

        // Initialize the buffer for outgoing messages
        mOutStringBuffer = new StringBuffer("");
    }
	
     
    
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.d(TAG, "onActivityResult " + resultCode);
        switch (requestCode) {
        case REQUEST_CONNECT_DEVICE_SECURE:
            // When DeviceListActivity returns with a device to connect
            if (resultCode == Activity.RESULT_OK) {
                connectDevice(data, true);
            }
            break;
         
        case REQUEST_ENABLE_BT:
        	Log.d(TAG, "HANDLING RESPONSE FROM REQUEST_ENABLE_BT");
            // When the request to enable Bluetooth returns
            if (resultCode == Activity.RESULT_OK) {
                // Bluetooth is now enabled, so set up a chat session
                setupBTCommunication();
            } else {
                // User did not enable Bluetooth or an error occurred
                Log.d(TAG, "BT not enabled");
                Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
                //finish();
            }
        }
    }

    private void connectDevice(Intent data, boolean secure) {
        // Get the device MAC address
        String address = data.getExtras()
            .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
        // Get the BluetoothDevice object
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
        // Attempt to connect to the device
        this.update_status_label(MESSAGE_CONNECTING_TO_DEVICE, device.getName());
        mChatService.connect(device, secure);
    }

	
	// -------  ENd of Bluetooth handling ----------------------------------- //
	
	
	
	public void resetGameAfterDelay(int delay_in_ms)
	{
	     new Handler().postDelayed(new Runnable(){
	        public void run() {
	        	  resetGame();
	        }}, delay_in_ms);
	}
	
	public void resetGame() {
		if (game!=null)
   		 game.reset(); 
		 MainActivity.imageAdapter.setAllToBlank();       
	 }

	   @Override
	    public boolean onCreateOptionsMenu(Menu menu) {
		   
		   this.menu = menu;
	        MenuInflater inflater = getMenuInflater();
	        inflater.inflate(R.menu.option_menu, menu);
	        
	        Intent prefsIntent = new Intent(this.getApplicationContext(),
			        TrisGamePreferences.class);
			MenuItem preferences = menu.findItem(R.id.options_menu);
			preferences.setIntent(prefsIntent);
			
			
			
	        return true;
	    }

	 
	    @Override
	    public boolean onOptionsItemSelected(MenuItem item) {
	        Intent serverIntent = null;
	        switch (item.getItemId()) {
	        
	        case R.id.options_menu:
	        	this.startActivity(item.getIntent());
	        	return true;
	        case R.id.secure_connect_scan:
	            // Launch the DeviceListActivity to see devices and do scan
	            serverIntent = new Intent(this, DeviceListActivity.class);
	            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
	            return true;
	        
	        case R.id.discoverable:
	            // Ensure this device is discoverable by others
	            //ensureDiscoverable();
	            return true;
	            
	        case R.id.quit_menu:
	        	this.exitDialog.show();
	        	return true;
	        }
	        return false;
	        
	    }
	    
	   private AlertDialog createExitDialog()
	   {
		// 1. Instantiate an AlertDialog.Builder with its constructor
		   AlertDialog.Builder builder = new AlertDialog.Builder(this);

		   // 2. Chain together various setter methods to set the dialog characteristics
		   builder.setMessage(R.string.exit_request);
		          //.setTitle(R.string.dialog_title);

		   
		// Add the buttons
		   builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
		              public void onClick(DialogInterface dialog, int id) {
		                  finish();
		              }
		          });
		   builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
		              public void onClick(DialogInterface dialog, int id) {
		                  // User cancelled the dialog
		              }
		          });
		   
		// 3. Get the AlertDialog from create()
		   AlertDialog dialog = builder.create();
          return dialog;
	   }
	   
	   private SoundPool createSoundPool()
	   {
		  SoundPool soundPool = new SoundPool(2,AudioManager.STREAM_MUSIC,0);
		  Toast.makeText(this, "Trying to load wav resource", Toast.LENGTH_LONG).show();
		  int sound_id = soundPool.load(this, R.raw.beep7,1);
		  soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
			
			@Override
			public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
				//this.local_player.setSoundID(sound_id);
				  soundPool.play(sampleId, 1, 1, 1, 2, 0.5f);
				
			}
		});
		
		  return soundPool;
	   }
	    
	 // The Handler that gets information back from the BluetoothChatService
	    private final Handler mHandler = new Handler() {
	        @Override
	        public void handleMessage(Message msg) {
	        	Log.d(TAG, "MESSAGE Handling: " + msg.what);
	            switch (msg.what) {
	            
	            case MESSAGE_STATE_CHANGE:
	                 Log.d(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
	                switch (msg.arg1) {
		                case BluetoothChatService.STATE_CONNECTED:
		                	Log.d(TAG, "MESSAGE_STATE_CONNECTED TO: " + mConnectedDeviceName);
		                    //setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));
		                    //mConversationArrayAdapter.clear();
		                	sendPlayerNameInfo();
		                	is_player_connected = true;
		                    break;
		                case BluetoothChatService.STATE_CONNECTING:
		                	Log.d(TAG, "MESSAGE_STATE_CONNECTING... ");
		                    //setStatus(R.string.title_connecting);
		                    break;
		                case BluetoothChatService.STATE_LISTEN:
		                case BluetoothChatService.STATE_NONE:
		                	Log.d(TAG, "MESSAGE_STATE_NONE (no connected) ");
		                    //setStatus(R.string.title_not_connected);
		                	update_status_label(MESSAGE_PLAYER_DISCONNECTED, null);
		                	is_player_connected = false;
		                	setConnection_accepted_from_remote_request(false);
		                    break;
		                }
		                break;
		                
	            case MESSAGE_WRITE:
	                byte[] writeBuf = (byte[]) msg.obj;
	                // construct a string from the buffer
	                String writeMessage = new String(writeBuf);
	                Log.d(TAG,"MESSAGE_WRITE:" + writeMessage);
	                //mConversationArrayAdapter.add("Me:  " + writeMessage);
	                break;
	            case MESSAGE_READ:
	                byte[] readBuf = (byte[]) msg.obj;
	                // construct a string from the valid bytes in the buffer
	                String readMessage = new String(readBuf, 0, msg.arg1);
	                Log.d(TAG,"MESSAGE_READ:" + readMessage);
	               // mConversationArrayAdapter.add(mConnectedDeviceName+":  " + readMessage);
	                parseMessage(readMessage);
	                break;
	            case MESSAGE_DEVICE_NAME:
	            	Log.d(TAG,"MESSAGE_DEVICE_NAME:" + msg.getData().getString(TOAST));
	                // save the connected device's name
	                mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
	                Toast.makeText(getApplicationContext(), "Connected to "
	                               + mConnectedDeviceName, Toast.LENGTH_SHORT).show();
	                
	                sendPlayerNameInfo();
	                break;
	                
	            case MESSAGE_TOAST:
	            	Log.d(TAG,"TOAST MESSAGE:" + msg.getData().getString(TOAST));
	                Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),
	                               Toast.LENGTH_LONG).show();
	                is_player_connected = false;
	                update_status_label(MESSAGE_PLAYER_DISCONNECTED, null);
	                break;
	                
	            case MESSAGE_CONNECTION_ACCEPTED_FROM_REMOTE_REQUEST:
	            	 
	                Toast.makeText(getApplicationContext(), msg.getData().getString(CONNECTION_ACCEPTED),
	                               Toast.LENGTH_LONG).show();
	                setConnection_accepted_from_remote_request(true);
	                break;
	                
	            case MESSAGE_CONNECTION_DONE_TO_REMOTE_REQUEST:
	            	 
	                Toast.makeText(getApplicationContext(), msg.getData().getString(CONNECTION_DONE_TO_REMOTE_REQUEST),
	                               Toast.LENGTH_LONG).show();
	                setConnection_accepted_from_remote_request(false);
	                break;
	            }
	        }
	    };
	    
	   
	    
	    @Override
	    public void onDestroy() {
	        super.onDestroy();
	        // Stop the Bluetooth chat services
	        if (mChatService != null) mChatService.stop();
	        Log.e(TAG, "--- ON DESTROY ---");
	    }

		protected void parseMessage(String readMessage) {
			
			if (readMessage.startsWith(PLAYER_NAME))
			{
				String player_name  = readMessage.split(":")[1];
				Toast.makeText(getApplicationContext(), "RECEIVED PLAYER NAME: "
                        + player_name, Toast.LENGTH_SHORT).show();
				
				
				update_status_label(MESSAGE_PLAYER_NAME, player_name);
				
            	
            	setRemotePlayerName( player_name );
            	initGame(player_name);
             
			}
			else
			remote_player_move(Integer.parseInt(readMessage));
			
		}
}
